package net.sh.dpinfrastructure.mongo;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.persistence.Column;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;


/**
 * 
 * Document 包装类
 * 
 * @version 1.0
 * @since JDK1.7
 * @author shaohui
 * @company 上海朝阳永续信息技术有限公司
 * @copyright (c) 2016 SunTime Co'Ltd Inc. All rights reserved.
 * @date 2016年4月12日 上午11:19:39
 */
public class DPDocument extends Document {
    
    private static final long serialVersionUID = 1L;
    
    public DPDocument() {
        super();
    }
    
    public DPDocument(Map<String, Object> keyValues) {
        super(keyValues);
    }

    public DPDocument(String key, Object value) {
        super(key, value);
    }
    
    public DPDocument append(String key, Object value) {
        super.append(key, value);
        return this;
    }
    
    /**
     * 
     * 判断是否包含指定key
     *
     * @param key
     * @return
     * 
     * @author shaohui
     * @date 2017年2月20日 上午10:45:50
     */
    public boolean containsKey(String key) {
        return super.containsKey(key);
    }
    
    @Override
    public boolean equals(final Object o) {
        return super.equals(o);
    }
    
    @Override
    public int hashCode() {
        return super.hashCode();
    }
    
    /**
     * 
     * 获取所有key
     *
     * @return
     * 
     * @author shaohui
     * @date 2017年2月20日 上午10:44:45
     */
    @Override
    public Set<String> keySet() {
        return super.keySet();
    }
    
    /**
     * 
     * 返回原始的被包装的 {@link Document}<br>
     * 只供包内调用
     *
     * @return
     * 
     * @author shaohui
     * @date 2017年2月20日 上午10:43:47
     */
    protected final Document toDocument() {
        return this;
    }

    /**
     * 
     * 将该对象转换成 {@link Map}
     *
     * @return
     * 
     * @author shaohui
     * @date 2017年2月20日 上午10:36:22
     */
    public Map<String, Object> toMap() {
        return this;
    }
    
    /**
     * 
     * 将原始字段名映射成别名
     * 
     * @param fieldsMapping
     * @return
     *
     * @author shaohui
     * @date 2017年2月19日上午11:11:43
     * @since JDK 1.8
     */
    public Map<String, Object> toMap(Map<String, String> fieldsMapping) {
        if (MapUtils.isEmpty(fieldsMapping)) {
            throw new IllegalArgumentException("empty field mapping");
        }
        Map<String, Object> resultMap = new HashMap<>();
        for (Map.Entry<String, Object> entry : this.entrySet()) {
            String originField = entry.getKey();
            String alias = fieldsMapping.get(originField);
            if (StringUtils.isEmpty(alias)) { // 没指定别名则使用原字段名
                alias = originField;
            }
            resultMap.put(alias, entry.getValue());
        }
        return resultMap;
    }
    
    /**
     * 
     * 将该document转换成需要类型<br/> 
     * 仅支持少数几种类型，复杂的请使用 {@link #toObject(DPResultMapper)}
     * 
     * @param clazz
     * @return
     *
     * @author shaohui
     * @throws IllegalAccessException 
     * @throws InstantiationException 
     * @date 2017年2月19日下午12:35:17
     * @since JDK 1.8
     */
    public <T> T toObject(Class<T> clazz) throws InstantiationException, IllegalAccessException {
        Field[] fields = clazz.getDeclaredFields();
        T result = clazz.newInstance();
        for (Field field : fields) {
            Column column = field.getAnnotation(Column.class);
            String columnName = column == null ? null : column.name();
            if (StringUtils.isBlank(columnName)) {
                columnName = field.getName();
            }
            Object value = this.get(columnName);
            if (value == null) {
                continue;
            }
            field.set(result, value);
        }
        return result;
    }
    
    /**
     * 
     * 将该document转换成需要类型
     * 
     * @param mapper
     * @return
     *
     * @author shaohui
     * @date 2017年2月19日上午11:08:01
     * @since JDK 1.8
     */
    public <T> T toObject(DPResultMapper<T> mapper) {
        return mapper.mapper(this);
    }
    
    @Override
    public String toString() {
        return super.toJson();
    }
    
    
}
